﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Pfz.Remoting;
using Pfz.Remoting.Serializers;
using Pfz.Serialization.BinaryBuiltIn;

namespace Pfz.Serialization
{
	internal sealed class RemotingSerializer:
		BinarySerializer
	{
		public RemotingSerializer()
		{
			Register(PropertyInfoSerializer.Instance);
			Register(MethodInfoSerializer.Instance);
			Register(EventInfoSerializer.Instance);
			Register(_FakeNullSerializer.Instance);

			Register(RemotingObjectSerializer.Instance);

			Register(Pfz.Remoting.Serializers.AddEventSerializer.Instance);
			Register(Pfz.Remoting.Serializers.CollectSerializer.Instance);
			Register(Pfz.Remoting.Serializers.CreateObjectSerializer.Instance);
			Register(Pfz.Remoting.Serializers.GetPropertySerializer.Instance);
			Register(Pfz.Remoting.Serializers.InvokeDelegateSerializer.Instance);
			Register(Pfz.Remoting.Serializers.InvokeMethodSerializer.Instance);
			Register(Pfz.Remoting.Serializers.InvokeStaticMethodSerializer.Instance);
			Register(Pfz.Remoting.Serializers.RemotingResultSerializer.Instance);
			Register(Pfz.Remoting.Serializers.RemoveEventSerializer.Instance);
			Register(Pfz.Remoting.Serializers.SetPropertySerializer.Instance);

			Register(Pfz.Remoting.Serializers._BackDelegateReferenceSerializer.Instance);
			Register(Pfz.Remoting.Serializers._BackObjectReferenceSerializer.Instance);
			Register(Pfz.Remoting.Serializers._ReferenceSerializer.Instance);
			Register(Pfz.Remoting.Serializers._WrappedSerializer.Instance);
			Register(Pfz.Remoting.Serializers._WrappedDelegateSerializer.Instance);
		}

		internal int _wrapCount;

		protected override IItemSerializer GetItemSerializerForUnregisteredType(Type type, Type deserializerWillExpectType)
		{
			if (!type.IsSerializable || typeof(IRemotable).IsAssignableFrom(type) || typeof(Delegate).IsAssignableFrom(type))
			{
				if (type != deserializerWillExpectType && Stream != null)
				{
					if (deserializerWillExpectType != null && !deserializerWillExpectType.IsSubclassOf(typeof(Delegate)) && deserializerWillExpectType != typeof(object) && !deserializerWillExpectType.IsInterface)
						throw new SerializationException("Can't serialize type " + type.FullName + " because it is not serializable and it is expected as an specific (non-remotable) type.");

					Stream.WriteByte(3);
				}

				return new RemotingObjectSerializer(type);
			}

			return base.GetItemSerializerForUnregisteredType(type, deserializerWillExpectType);
		}

		protected override IItemSerializer GetItemDeserializerForUnregisteredType(Type type, Type expectedType)
		{
			if (!type.IsSerializable || typeof(IRemotable).IsAssignableFrom(type) || typeof(Delegate).IsAssignableFrom(type))
				return new RemotingObjectSerializer(type);

			return base.GetItemDeserializerForUnregisteredType(type, expectedType);
		}
	}
}
